/*
 * CTalent.java
 *
 * Copyright (c) 2009 Giles Millward (Manigra). All rights reserved.
 *
 * This file is part of JRogueDPS.
 *
 * JRogueDPS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JRogueDPS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JRogueDPS.  If not, see <http://www.gnu.org/licenses/>.
 */
package talents;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.RenderingHints;
import utility.CUtility;
import jroguedps.*;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.InputEvent;
import java.awt.image.BufferedImage;
import java.util.Collection;
import java.util.Iterator;


public class CTalent {

    enum TalentColor {UNAVAILABLE, AVAILABLE, PARTIAL, MAXED};


    final static int    c_xSpacing = 12;
    final static int    c_ySpacing = 8;
    final static int    c_xTreeSpacing = 60;
    final static int    c_initialXOffset = 40;
    final static int    c_initialYOffset = 50;
    final static int    c_imageWidth = 33;
    final static int    c_imageHeight = 33;
    final static int    c_textXOffset = c_imageWidth - 10;
    final static int    c_textYOffset = c_imageHeight - 15;

	private String m_name;
	private int	m_maxPoints;
	private int m_currentPoints;
	private int m_tier;
    private int m_requiredPoints;
    private String m_dependency;
	private String m_tree;
    private CTalentToolTip m_toolTip;
    private ImageIcon m_colorIcon;
    private ImageIcon m_grayIcon;
    private JLabel m_jLabelImage;
    private JLabel m_jLabelPoints;
    private boolean m_available;
    private CTalentTree m_talentTree; // Parents
    private CRogueTalents m_talentClass; // Parents

	CTalent(String p_name, String p_tree, int p_tier, int p_maxPoints, int p_xIndex, String p_dependency) {
		setName(p_name);
		setTree(p_tree);
		setMaxPoints(p_maxPoints);		
        setTier(p_tier);
        setRequiredPoints((getTier() - 1) * 5);
        setDependency(p_dependency);
        m_toolTip = new CTalentToolTip();

        String l_niceFileName = p_tree.toLowerCase() + "_" + p_name.replaceAll("\\s+", "").toLowerCase();

        ImageIcon l_colorIcon;
        ImageIcon l_grayIcon;

        // When the image file is in another package of the jar file.
        if (CGlobal.g_writeImagesToDisk)
        {
            l_colorIcon = CUtility.getTalentIcon(p_tree, p_name, true);
            l_grayIcon = CUtility.getTalentIcon(p_tree, p_name, false);
        }
        else
        {
            ClassLoader cl = getClass().getClassLoader();
            l_colorIcon = new ImageIcon(cl.getResource("jroguedps/images/" + l_niceFileName + ".jpg"));
            l_grayIcon = new ImageIcon(cl.getResource("jroguedps/images/" + l_niceFileName + "_gray.jpg"));
        }



        m_colorIcon = new ImageIcon(CUtility.getScaledInstance(CUtility.getBufferedImageFromImageIcon(l_colorIcon), c_imageWidth, c_imageHeight, RenderingHints.VALUE_INTERPOLATION_BICUBIC, true));
        m_grayIcon = new ImageIcon(CUtility.getScaledInstance(CUtility.getBufferedImageFromImageIcon(l_grayIcon), c_imageWidth, c_imageHeight, RenderingHints.VALUE_INTERPOLATION_BICUBIC, true));

        // Setup position of talent icons and text
        m_jLabelImage = new javax.swing.JLabel();
        m_jLabelImage.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0), 1, true));
        m_jLabelImage.setMaximumSize(new java.awt.Dimension(c_imageWidth, c_imageHeight));
        m_jLabelImage.setMinimumSize(new java.awt.Dimension(c_imageWidth, c_imageHeight));
        int l_xPos = c_initialXOffset + ((p_xIndex - 1) * (c_imageWidth + c_xSpacing));
        if (p_tree.toLowerCase().equals("combat"))
        {
           // Combat
            l_xPos += ((4 * c_imageWidth) + (3 * c_xSpacing) + c_xTreeSpacing);
        }
        else if (p_tree.toLowerCase().equals("subtlety"))
        {
            // Subtlety
            l_xPos += ((8 * c_imageWidth) + (6 * c_xSpacing) + (c_xTreeSpacing * 2));
        }

        int l_yPos = c_initialYOffset + ((p_tier - 1) * (c_imageHeight + c_ySpacing));
        m_jLabelImage.setBounds(l_xPos, l_yPos, c_imageWidth, c_imageHeight);
        m_jLabelImage.setIcon(m_grayIcon);

        m_jLabelPoints = new javax.swing.JLabel();
        m_jLabelPoints.setBackground(new java.awt.Color(0, 0, 0));
        m_jLabelPoints.setFont(new java.awt.Font("Arial Narrow", 0, 12)); // NOI18N
        m_jLabelPoints.setForeground(new java.awt.Color(153, 255, 51));
        m_jLabelPoints.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        m_jLabelPoints.setText(getTextCurrent());
        m_jLabelPoints.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(51, 204, 0), 2, true));
        m_jLabelPoints.setOpaque(true);
        m_jLabelPoints.setBounds(l_xPos + c_textXOffset, l_yPos + c_textYOffset , 20, 20);
        m_currentPoints = -1;
        if (p_tier == 1)
        {
            m_available = true;
        }
        else
        {
            m_available = false;
        }
        
        m_jLabelImage.addMouseListener(new MouseAdapter()
        {
            @Override
            public void mouseReleased(MouseEvent e)
            {
                if ((e.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
                {
                    setCurrentPoints(getCurrentPoints() - 1, true);
                }
                else if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK)
                {
                    setCurrentPoints(getCurrentPoints() + 1, true);
                }
            }
        });
	}


    public void setParents(CTalentTree p_talentTree, CRogueTalents p_talentClass)
    {
        m_talentTree = p_talentTree;
        m_talentClass = p_talentClass;
    }
    
	public String getName() {
		return m_name;
	}
	public void setName(String name) {
		m_name = name;
	}
	
	public String getTree() {
		return m_tree;
	}
	public void setTree(String tree) {
		m_tree = tree;
	}
	
	public int getMaxPoints() {
		return m_maxPoints;
	}
	public void setMaxPoints(int points) {
		m_maxPoints = points;
	}
	public int getCurrentPoints() {
		return m_currentPoints;
	}
    public void setCurrentPoints(int p_points, boolean p_validatePoints) {
        int m_previousPoints = m_currentPoints;
        int l_maxTalents;

        if (p_points > m_maxPoints) {
            p_points = m_maxPoints;
        } else if (p_points < 0) {
            p_points = 0;
        }

        int m_deltaPoints = p_points - m_previousPoints;

        if (p_points != m_currentPoints) {
            if (p_validatePoints) {
                // Are there enough total points available ?
                if ((m_talentClass.getTotalPoints() + m_deltaPoints) > m_talentClass.getMaxPoints()) {
                    // Doing this would go past the limit of points available
                    System.out.println("Not enough talent points left");
                    return;
                }

                // Are there enough points already in the tree for this ?
                if (m_talentTree.getTotalPoints() < this.getRequiredPoints()) {
                    return;
                }

                // If this talent has a requirement of another talents being at max points
                if (m_dependency != null && m_deltaPoints > 0) {
                    CTalent l_dependency = m_talentClass.getTalent(m_dependency);
                    if (l_dependency.getMaxPoints() != l_dependency.getCurrentPoints()) {
                        System.out.println("Talent point requires talents in " + l_dependency.getName());
                        l_dependency.m_jLabelImage.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(255, 0, 0), 2, true));
                    }
                }

                // Would dropping this talent point cause problems for other talents
                if (m_deltaPoints < 0) {
                    // If this talent is relied upon by another talent to be set
                    // then don't allow the change
                    CTalent l_talent = m_talentTree.findDependentTalent(this.getName());
                    if (l_talent != null) {
                        // Another talent is dependent on this one being set
                        if (l_talent.getCurrentPoints() > 0) {
                            System.out.println("Talent " + l_talent.getName() + " requires this talent to be at max points");
                            l_talent.m_jLabelImage.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(255, 0, 0), 2, true));
                            return;
                        }
                    }

                    // Dropping this talent might cause problems for talents higher
                    // up the tree
                    l_maxTalents = m_talentTree.getMaxTalents();
                    int l_totalPoints = 0;
                    m_currentPoints += m_deltaPoints;
                    for (int i = 0; i < l_maxTalents; i ++)
                    {
                        l_talent = m_talentTree.getTalent(i);
                        if (l_talent.getCurrentPoints() > 0 &&
                                l_totalPoints < l_talent.getRequiredPoints())
                        {
                            System.out.println("Changing this talent will cause other talents like [" + l_talent.getName() + "] to be invalid");
                            m_currentPoints = m_previousPoints;
                            return;
                        }
                        l_totalPoints += l_talent.getCurrentPoints();
                    }

                    m_currentPoints = m_previousPoints;
                }
            }

            m_currentPoints = p_points;
            if (m_currentPoints == 0) {
                m_jLabelImage.setIcon(m_grayIcon);
            } else if (m_previousPoints == 0) {
                m_jLabelImage.setIcon(m_colorIcon);
            }
 
        
            m_jLabelPoints.setText(getTextCurrent());
            m_jLabelImage.setToolTipText(m_toolTip.buildToolTip(this));

            // Re-scan each tree to check new available talents or if we are
            // locked out completely, this is just to change the colors things
            // if we need to.
            if (m_talentClass.getTotalPoints() == m_talentClass.getMaxPoints())
            {
                System.out.println("Total points max out!");
                Collection c = m_talentClass.getTalentHashMap().values();

                //obtain an Iterator for Collection
                Iterator itr = c.iterator();

                //iterate through HashMap values iterator
                while(itr.hasNext())
                {
                    CTalent l_talent = (CTalent) itr.next();
                    if (l_talent.getCurrentPoints() == 0)
                    {
                        l_talent.setColor(TalentColor.UNAVAILABLE);
                    }
                }
            }
            else
            {
                // Check if changing this talent opens up or closes other talents
                for (int i = 0; i < 3; i++)
                {
                    CTalentTree l_talentTree = m_talentClass.getTalentTree(i);
                    int l_totalPoints = l_talentTree.getTotalPoints();
                    l_maxTalents = l_talentTree.getMaxTalents();

                    for (int j = 0; j < l_maxTalents; j ++)
                    {
                        CTalent l_talent = l_talentTree.getTalent(j);

                        // First tier is usually open
                        if (l_talent.getTier() == 1)
                        {
                            if (l_talent.getCurrentPoints() == 0 &&
                                    !l_talent.getAvailable())
                            {
                                l_talent.setColor(TalentColor.AVAILABLE);
                            }
                        }
                        else   
                        {
                            // Tier 2 and above
                            if (l_talent.getCurrentPoints() == 0)
                            {
                                if (!l_talent.getAvailable())
                                {
                                    if (l_talent.getRequiredPoints() <= l_totalPoints)
                                    {
                                        l_talent.setColor(TalentColor.AVAILABLE);
                                    }
                                }
                                else
                                {
                                    if (l_talent.getRequiredPoints() > l_totalPoints)
                                    {
                                        l_talent.setColor(TalentColor.UNAVAILABLE);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (m_maxPoints == m_currentPoints)
            {
                setColor(TalentColor.MAXED);
            }
            else
            {
                if (m_currentPoints == 0)
                {
                    setColor(TalentColor.AVAILABLE);
                }
                else
                {
                    setColor(TalentColor.PARTIAL);
                }
            }
        }

        m_talentTree.updateTotalPoints();
        m_talentClass.updateTextTotals();
        CGlobal.g_rootFrame.setStats();
    }

    private void setColor(TalentColor p_color)
    {
        if (p_color == TalentColor.AVAILABLE)
        {
            // Grey image border but green text and border for points
            m_jLabelImage.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0), 1, true));
            m_jLabelPoints.setForeground(new java.awt.Color(153, 255, 51));
            m_jLabelPoints.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(51, 204, 0), 2, true));
            setAvailable(true);
        } else if (p_color == TalentColor.MAXED)
        {
            // Orange
            m_jLabelPoints.setForeground(new java.awt.Color(241, 201, 0));
            m_jLabelPoints.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(241, 201, 0), 2, true));
            m_jLabelImage.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(241, 201, 0), 2, true));
        } else if (p_color == TalentColor.PARTIAL)
        {
            // Greeen image border and green text and border
            m_jLabelImage.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(51, 204, 0), 2, true));
            m_jLabelPoints.setForeground(new java.awt.Color(153, 255, 51));
            m_jLabelPoints.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(51, 204, 0), 2, true));
        } else if (p_color == TalentColor.UNAVAILABLE)
        {
            // Grey border, grey text and border
            m_jLabelImage.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0), 1, true));
            m_jLabelPoints.setForeground(new java.awt.Color(100, 100, 100));
            m_jLabelPoints.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(100, 100, 100), 2, true));
            setAvailable(false);
        }
    }

	public int getTier() {
		return m_tier;
	}
	public void setTier(int tier) {
		m_tier = tier;
	}

	public int getRequiredPoints() {
		return m_requiredPoints;
	}
	public void setRequiredPoints(int requiredPoints) {
		m_requiredPoints = requiredPoints;
	}
    
	public String getDependency() {
		return m_dependency;
	}
	public void setDependency(String dependency) {
		m_dependency = dependency;
	}

    private String getTextCurrent()
    {
        return getCurrentPoints() + "/" + getMaxPoints();
    }
    public JLabel getIcon()
    {
        return m_jLabelImage;
    }

    public JLabel getText()
    {
        return m_jLabelPoints;
    }

    public CTalentToolTip getToolTip()
    {
        return m_toolTip;
    }

    public CRogueTalents getTalentClass()
    {
        return m_talentClass;
    }

    public void setAvailable(boolean p_available)
    {
        m_available = p_available;
    }

    public boolean getAvailable()
    {
        return m_available;
    }


}
